﻿/*
 *Copyright(C) 2024 by CometGamming All rights reserved.
 *Unity版本：2022.3.43f1c1 
 *作者:程一峰  
 *创建日期: 2024-10-13 
 *模块说明：简易状态机
 *版本: 0.1.0
*/

using Sirenix.OdinInspector;
using System;
using System.Collections.Generic;

namespace Warfare.FSM
{
    /// <summary>
    /// 单个状态
    /// <summary>
    [Serializable, HideReferenceObjectPicker]
    public class FSMState
    {

        [LabelText("节点ID")]
        [DisplayAsString]
        public int ConfigID { get; internal set; }

        [LabelText("配置名字")]
        [DisplayAsString]
        public string Name { get; internal set; }

        [LabelText("节点行为")]
        [ReadOnly]
        public List<FSMNodeAction> Actions = new List<FSMNodeAction>();

        [LabelText("是否取反")]
        [DisplayAsString]
        public bool IsTwist { get; internal set; }

        internal FSMState(FSMMachine machine, FSMNode node)
        {
            this.machine = machine;
            m_CurrentActionIndex = 0;
            ConfigID = node.Index;
            if (node.Actions != null)
                Actions = new List<FSMNodeAction>(node.Actions);
            IsTwist = node.IsTwist;
            NextSucessStateIndex = node.SucessNodeIndex;
            NextFailedStateIndex = node.FailedNodeIndex;
            Name = node.NodeName;
        }

        public FSMMachine machine { get; private set; }
        public I_FSMContext context => machine?.Context;
        public I_FSMActor actor => machine?.Actor;

        /// <summary>
        /// 成功的下一个节点
        /// </summary>
        public int NextSucessStateIndex { get; private set; }
        private FSMState m_NextSucessState;
        private FSMState NextSucessState
        {
            get
            {
                if (m_NextSucessState == null)
                    m_NextSucessState = machine?.FindFSMState(NextSucessStateIndex);
                return m_NextSucessState;
            }
        }

        /// <summary>
        /// 失败的下一个节点
        /// </summary>
        public int NextFailedStateIndex { get; private set; }
        private FSMState m_NextFailedState;
        private FSMState NextFailedState
        {
            get
            {
                if (NextFailedState == null)
                    m_NextFailedState = machine?.FindFSMState(NextFailedStateIndex);
                return NextFailedState;
            }
        }


        /// <summary>
        /// 当前运行的节点下标；
        /// </summary>
        private int m_CurrentActionIndex;
        private FSMNodeAction m_CurrentAction;

        public void OnEnter()
        {
            m_CurrentActionIndex = -1;
            m_CurrentAction = null;
        }

        /// <summary>
        /// 更新，返回true表示结束，false表示继续；
        /// </summary>
        /// <returns></returns>
        public E_MachineState Update(float deltaTime)
        {
            var state = UpdateAllActions(deltaTime);
            switch (state)
            {
                case E_MachineState.Sucess:
                    GoNextState(true);
                    break;
                case E_MachineState.Failed:
                    GoNextState(false);
                    break;
                case E_MachineState.None:
                case E_MachineState.Error:
                    machine.Run();
                    return E_MachineState.Error;
            }
            return E_MachineState.Running;
        }

        private void GoNextState(bool sucess)
        {
            if (IsTwist)
                sucess = !sucess;

            var next = sucess ? NextSucessState : NextFailedState;
            machine.Run(next);
        }

        private E_MachineState UpdateAllActions(float deltaTime)
        {
            if (m_CurrentActionIndex < 0)
            {
                m_CurrentActionIndex++;
                m_CurrentAction = null;
                return E_MachineState.Running;
            }

            if (m_CurrentActionIndex >= Actions.Count)
                return E_MachineState.Sucess;

            var action = Actions[m_CurrentActionIndex];
            if (action != m_CurrentAction)
            {
                m_CurrentAction = action;
                m_CurrentAction.OnEnter(context, actor);
            }

            var state = m_CurrentAction.Update(deltaTime);
            switch (state)
            {
                case E_MachineState.Sucess:
                    m_CurrentActionIndex++;
                    break;
                case E_MachineState.Failed:
                    return E_MachineState.Failed;
                case E_MachineState.None:
                case E_MachineState.Error:
                    return E_MachineState.Error;
            }
            return E_MachineState.Running;
        }


        public override string ToString() => $"[FSMState]_{ConfigID}: {Name} : {m_CurrentActionIndex}";


    }
}